
package com.rt.gptnext.common.utils.http;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.URLUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.rt.gptnext.common.utils.SafeUtil;

import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import static com.rt.gptnext.common.utils.http.HttpLogLevel.BODY;


/**
 * @author gaoyiyang
 **/
public abstract class HttpEngine {

    /**
     * 日志输出工具
     *
     * @return 日志工具
     */
    protected Log log() {
        return LogFactory.get(this.getClass());
    }

    /**
     * 发送请求
     *
     * @param request 请求元素
     * @param info    请求信息
     */
    protected abstract void requestImpl(HttpRequest request, HttpInfo info);

    /**
     * 请求响应流
     *
     * @param request  请求元素
     * @param consumer 流消费者
     * @param block    阻塞器
     * @param info     请求信息
     * @param end      结束时调用
     */
    protected abstract void requestStreamImpl(HttpRequest request, Consumer<HttpStream> consumer, CountDownLatch block, HttpInfo info, Runnable end);

    /**
     * 请求响应流
     *
     * @param request  请求元素
     * @param consumer 流消费者
     * @param block    阻塞器
     */
    public void requestStream(HttpRequest request, Consumer<HttpStream> consumer, CountDownLatch block) {
        // 初始化请求信息
        var info = initInfo(request);
        // 实际请求
        requestStreamImpl(request, consumer, block, info, () -> endInfo(request, info));
    }

    /**
     * 发送请求
     *
     * @param request 请求元素
     * @return 响应结果
     */
    public HttpResponse<byte[]> request(HttpRequest request) {
        // 初始化请求信息
        var info = initInfo(request);
        // 实际请求
        requestImpl(request, info);
        // 构造响应对象
        var response = HttpResponse.create(info);
        // 校验请求是否成功
        try {
            info.setSuccess(request.getValidator().valid(response));
        } catch (Exception e) {
            info.setSuccess(false);
            log().error("数据校验报错", e);
        }
        response.setValidateSuccess(info.isSuccess());
        endInfo(request, info);
        return response;
    }

    private HttpInfo initInfo(HttpRequest request) {
        HttpInfo info = new HttpInfo();
        info.setApiName(request.getApiName());
        info.setBusinessId(request.getBusinessId());
        info.setGroup(request.getGroup());
        info.setMethod(request.getMethod());
        info.setStartTime(System.currentTimeMillis());
        info.setOriginUrl(request.getUrl());
        info.setDownload(request.isDownload());
        // 添加cookie
        if (CollUtil.isNotEmpty(request.getCookies())) {
            String cookieStr = request.getCookies().entrySet().stream()
                    .map(cookie -> cookie.getKey() + "=" + cookie.getValue())
                    .collect(Collectors.joining("; "));
            request.header("Cookie", cookieStr);
        }
        return info;
    }

    private void endInfo(HttpRequest request, HttpInfo info) {
        info.setEndTime(System.currentTimeMillis());
        info.setTime(info.getEndTime() - info.getStartTime());
        // 打印日志
        if (request.isPrintLog()) {
            log().info(info.toLog(BODY, 1000));
        }
        try {
            if (SpringUtil.getApplicationContext() != null
                    || SpringUtil.getBeanFactory() != null) {
                var saverMap = SpringUtil.getBeansOfType(InfoSaver.class);
                if (saverMap != null) {
                    for (InfoSaver saver : saverMap.values()) {
                        SafeUtil.call(() -> saver.save(info));
                    }
                }
            }
        } catch (Exception ignored) {
        }
    }

    /**
     * 处理url
     *
     * @param request 请求对象
     * @param info    请求信息
     * @return url
     */
    protected String handleUrl(HttpRequest request, HttpInfo info) {
        String url = request.getUrl();
        if (CollUtil.isNotEmpty(request.getForm())) {
            // 拼接请求url
            StringBuilder queryString = new StringBuilder();
            request.getForm().forEach((k, v) ->
                    queryString.append(k).append("=").append(URLUtil.encodeAll(toStr(v))).append("&")
            );
            url = HttpUtil.urlWithForm(request.getUrl(), queryString.substring(0, queryString.length() - 1), StandardCharsets.UTF_8, false);
        }
        info.setUrl(url);
        return url;
    }

    /**
     * 对象转换为字符串，用于URL的Query中
     *
     * @param value 值
     * @return 字符串
     */
    protected static String toStr(Object value) {
        String result;
        if (value instanceof Iterable) {
            result = CollUtil.join((Iterable<?>) value, ",");
        } else if (value instanceof Iterator) {
            result = IterUtil.join((Iterator<?>) value, ",");
        } else {
            result = Convert.toStr(value);
        }
        return result;
    }

}
